The format of each line in the ``address-file'' is as follows:
Each line from standard input is sent to standard output, preceded with an ``OK'' if the host is not guilty of IP forwarding, or with a ``NOTOK'' otherwise.
The ipforwarding program checks for IP forwarding by manufacturing a special ethernet packet that has a unicast Ethernet address and a new-style broadcast IP address and sending it out via Sun's NIT facility. If the target host echos this packet, it is deemed guilty of IP forwarding. Note that if the target host happens to be down, it will be (possibly incorrectly) deemed not guilty of IP forwarding.
Does not check for bad ICMP replies that are also capable of causing broadcast storms.
Will exonerate any host that is down.
/*
* $Log: ipforwarding.c,v $
* Revision 1.1 87/12/08 10:16:58 mckenney
* Initial revision
*
*/
/* Include files. */
#include <stdio.h> #include <sys/types.h> #include <sys/signal.h> #include <sys/socket.h> #include <sys/time.h> #include <net/if.h> #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <netinet/ip.h> #include <net/nit.h> #include <netdb.h> #include <setjmp.h>
/* Type definitions local to this file. */
#define MAXTRIES 5 /* MAX. # transmit TRIES. */
#define WAITTIME 1000000L /* WAIT TIME between tries. */
struct ether_ip
{
struct ether_header eh;
struct ip ip;
};
struct ether_iparp
{
struct ether_header eh;
struct ether_arp arp;
};
/* Functions exported from this file. */
/* Functions local to this file. */
static void catchalrm(); /* CATCH sigALRM's. */
static int catchpkt(); /* CATCH ethernet PacKeTs. */
/* Variables exported from this file. */
/* Variables local to this file. */
static int badhost; /* is this a BAD HOST? */
jmp_buf env; /* ENVironment. */
struct ether_ip packet; /* outbound PACKET. */
main(argc, argv)
int argc;
char *argv[];
{
char cea[30]; /* Character version of EA. */
char cia[30]; /* Character version of Ip Addr.*/
struct ether_addr ea; /* Ethernet Address. */
char *em; /* Error Message pointer. */
char hostname[BUFSIZ]; /* HOST NAME buffer. */
int i;
struct itimerval itv; /* Interval Timer Value. */
char line[BUFSIZ]; /* input LINE. */
int nitin; /* NIT INput socket. */
int nitout; /* NIT OUTput socket. */
int ntries; /* Number of TRIES at output. */
int retval; /* RETurn VALue. */
struct sockaddr_in sa; /* current Socket Address. */
/* Check parameters. */
if ((argc < 2) ||
(argc > 3))
{
fprintf(stderr, "Usage: %s interface [IPaddr], argv[0]);
exit (-1);
}
/* Set up NIT sockets for raw ethernet interface. */
switch (nitout = mk_nit_snd(argv[1], &em))
{
case -1:
fprintf(stderr, "Can't open NIT output: ");
perror(em);
exit(-1);
case -2:
fprintf(stderr, "Can't open NIT output: ");
fprintf(stderr, "%s, em);
exit(-1);
}
switch (nitin = mk_nit_chaste_filt(argv[1],
ETHERTYPE_ARP,
sizeof(struct ether_header) +
sizeof(struct ether_arp),
WAITTIME,
&em))
{
case -1:
fprintf(stderr, "Can't open NIT input: ");
perror(em);
exit(-1);
case -2:
fprintf(stderr, "Can't open NIT input: ");
fprintf(stderr, "%s, em);
exit(-1);
}
/* Find out who we are. */
(void)gethostname(hostname, sizeof(hostname));
switch (tx_hostname(hostname, &sa, &em))
{
case -1:
fprintf(stderr, "Can't find my name: ");
perror(em);
exit(-1);
case -2:
fprintf(stderr, "Can't find my name: ");
fprintf(stderr, "%s, em);
exit(-1);
}
/* Initialize the ethernet message type on the outgoing packet. */
packet.eh.ether_type = ETHERTYPE_IP;
/* Initialize the IP portion of the packet. */
packet.ip.ip_v = IPVERSION;
packet.ip.ip_hl = sizeof(struct ip) / 4;
packet.ip.ip_tos = 0;
packet.ip.ip_len = sizeof(struct ip);
packet.ip.ip_id = 123;
packet.ip.ip_off = 0;
packet.ip.ip_ttl = 255;
packet.ip.ip_p = 61;
packet.ip.ip_sum = 0;
packet.ip.ip_src = sa.sin_addr;
packet.ip.ip_dst = sa.sin_addr;
if (argc > 2)
packet.ip.ip_dst.S_un.S_addr = inet_addr(argv[2]);
else if (IN_CLASSA(packet.ip.ip_dst.S_un.S_addr))
{
packet.ip.ip_dst.S_un.S_un_b.s_b2 = 255;
packet.ip.ip_dst.S_un.S_un_b.s_b3 = 255;
packet.ip.ip_dst.S_un.S_un_b.s_b4 = 255;
}
else if (IN_CLASSB(packet.ip.ip_dst.S_un.S_addr))
{
packet.ip.ip_dst.S_un.S_un_b.s_b3 = 255;
packet.ip.ip_dst.S_un.S_un_b.s_b4 = 255;
}
else if (IN_CLASSC(packet.ip.ip_dst.S_un.S_addr))
packet.ip.ip_dst.S_un.S_un_b.s_b4 = 255;
/* Set up to catch alarm signals. */
signal(SIGALRM, catchalrm);
/* Each pass through the following loop probes one host for */
/* the ipforwarding bug. */
while (fgets(line, sizeof(line), stdin) != NULL)
{
struct sockaddr_in dsa; /* Destination Socket Address. */
/* Break out the ethernet and IP addresses. */
/* Question (but otherwise ignore) bad lines. */
if (sscanf(line, "%25s %25s", cea, cia) != 2)
{
printf("%-6s %s", "???", line);
continue;
}
if (!atoether(cea, &packet.eh.ether_dhost))
{
printf("%-6s %s", "?ea", line);
continue;
}
if (tx_hostname(cia, &dsa, &em) < 0)
{
printf("%-6s %s", "?ia", line);
continue;
}
/* Set up context for timeout. */
ntries = 0;
if (!setjmp(env) ||
(++ntries < MAXTRIES))
{
/* Transmit packet. */
if (nit_write(nitout, &packet, sizeof(packet)) < 0)
{
perror("nit_write failed");
exit(-1);
}
/* Set timer to wake us up after a second. */
timerclear(&itv.it_interval);
itv.it_value.tv_sec = 1L;
itv.it_value.tv_usec = 0L;
(void)setitimer(ITIMER_REAL,
&itv,
(struct itimerval *)NULL);
/* Read ethernet packets . . . */
badhost = 0;
if (nit_read(nitin, catchpkt, &em) < 0)
{
perror("nit_read failed");
exit(-1);
}
}
/* Print out the input line with the appropriate */
/* preface string. */
(void)printf("%-5s %s", badhost ? "NOTOK" : "OK", line);
fflush(stdout);
}
exit (0);
}
/* CATCH sigALRM signal, abort back to top level. */
static void catchalrm()
{
longjmp(env);
}
/* CATCH ethernet PacKeT. */
static int catchpkt(nh, pk, len)
struct nit_hdr *nh; /* Nit Header. */
char *pk; /* PacKet. */
int len; /* LENgth of pk. */
{
struct ether_iparp *arp /* ARP packet pointer. */
= (struct ether_iparp *)pk;
int i;
/* If we have nothing to look at, leave. */
if (pk == NULL)
return (1);
/* Sanity check on len. */
if (len < sizeof(*arp))
return (1);
/* Ignore any packets that are not arp requests. */
if (arp->arp.arp_op != ARPOP_REQUEST)
return (1);
/* Ignore any packets that are not broadcasts. */
for (i = 0; i < sizeof(arp->eh.ether_dhost); i++)
if (arp->eh.ether_dhost.ether_addr_octet[i] != 0xff)
return (1);
/* Ignore any packets that are not from the current host. */
if (bcmp(&arp->eh.ether_shost,
&packet.eh.ether_dhost,
sizeof(arp->eh.ether_shost)) != 0)
return (1);
/* Ignore any packets that are not arp-ing for the broadcast */
/* address. */
if (bcmp(arp->arp.arp_xtpa,
&packet.ip.ip_dst,
sizeof(arp->arp.arp_xtpa)) != 0)
return (1);
/* He's bad, set the flag. Do not tell the caller that we have */
/* seen enough so that we don't have to worry about the timer. */
badhost = 1;
return (0);
}
RogueMonsterelse
echo "will not overwrite ./ipforwarding.c"
fi
if [ `wc -c ./ipforwarding.c | awk '{printf $1}'` -ne 7467 ]
then
echo `wc -c ./ipforwarding.c | awk '{print "Got " $1 ", Expected " 7467}'`
fi
if `test ! -s ./nit.3`
then
echo "writing ./nit.3"
cat > ./nit.3 << 'RogueMonster'
mk_nit_snd - Make NIT output socket mk_nit_chaste - Make ``chaste'' NIT input socket mk_nit_chaste_filt - Make ``chaste'' filtered NIT input socket mk_nit_promisc - Make promiscuous NIT input socket mk_nit_promisc_filt - Make promiscuous filtered NIT input socket mk_nit_rcv - Make specified type of NIT input socket nit_read - NIT socket read/decode routine
int mk_nit_snd(device, errmsg) char *device; char **errmsg; int mk_nit_chaste(device, snaplen, tout, errmsg) char *device; int snaplen; unsigned long tout; char **errmsg; int mk_nit_chaste_filt(device, pktype, snaplen, tout, errmsg) char *device; unsigned int pktype; int snaplen; unsigned long tout; char **errmsg; int mk_nit_promisc(device, snaplen, tout, errmsg) char *device; int snaplen; unsigned long tout; char **errmsg; int mk_nit_promisc_filt(device, pktype, snaplen, tout, errmsg) char *device; unsigned int pktype; int snaplen; unsigned long tout; char **errmsg; int mk_nit_rcv(device, promiscuous, pktype, snaplen, tout, errmsg) char *device; int promiscuous; unsigned int pktype; int snaplen; unsigned long tout; char **errmsg; int nit_read(fd, rtn, errmsg) int fd; int (*rtn)(); char **errmsg; int nit_write(fd, buf, len) int fd; char *buf; int len;
The routines `mk_nit_chaste', `mk_nit_chaste_filt', `mk_nit_promisc', `mk_nit_nit_promisc_filt', and `mk_nit_rcv' all create NIT sockets suitable for reading raw packets from the specified interface. These routines allow various options:
The `nit_read' routine breaks the kernel's buffer down into packets, which it feeds one at a time to the function passed in through `rtn'. The `rtn' function will be called for every NIT header block present in the buffer. An NIT header block is present for each packet, for each group of lost packets (when you program is too slow to catch them!), and for the unlikely case that the timeout specified by the `tout' parameter to the routine that created the NIT socket expired without any packets showing up.
The `rtn' function will be passed three parameters:
The `rtn' function should return a `1' if it wishes to continue to receive packets, or a `0' if it has seen enough.
The `nit_write' routine dumps the contents of the specified buffer to the interface in raw mode. Note that the kernel may modify the source ethernet address to better reflect reality, and that the packet may be padded to fit size limitations.
/*
* $Log: nit.c,v $
* Revision 2.0 88/09/23 18:28:16 mckenney
* .
*
* Revision 1.2 87/11/18 09:57:07 mckenney
* Add nit_write routine.
*
* Revision 1.1 87/11/18 09:45:11 mckenney
* Initial revision
*
*/
/* Include files. */
#include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/nit.h> #include <net/if.h>
/* Type definitions local to this file. */
#define BUFSPACE (4 * 8192) /* kernel nit BUFfer SPACE. */
/* Functions exported from this file. */
extern int mk_nit_snd(); /* MaKe NIT socket for SeNDing. */
extern int mk_nit_chaste(); /* MaKe NIT for CHASTE rcv. */
extern int mk_nit_chaste_filt(); /* same, w/ type FILTer. */
extern int mk_nit_promisc(); /* MaKe NIT for PROMISC. rcv. */
extern int mk_nit_promisc_filt(); /* same, w/ type FILTer. */
extern int mk_nit_rcv(); /* MaKe NIT for ReCeiVe. */
extern int nit_read(); /* NIT socket READ/decode. */
extern int nit_write(); /* NIT socket WRITE packet. */
/* Functions local to this file. */
/* Variables exported from this file. */
/* Variables local to this file. */
/* MaKe an NIT socket for SeNDing arbitrary packets on the device whose */
/* name is passed as a string through `device'. This is currently */
/* only guaranteed to work on ethernet devices. Returns a file */
/* descriptor if all goes well, or -1 if not (in this case errno will */
/* set to the error number, and errmsg will be pointed to a string that */
/* describes the attempted operation). */
extern int mk_nit_snd(device, errmsg)
char *device; /* name of DEVICE to send on. */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
int fd; /* File Descriptor. */
struct nit_ioc nioc; /* Nit IOCtl parameter block. */
struct sockaddr_nit snit; /* Sockaddr for NIT socket. */
/* Make the socket. */
if ((fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW)) == -1)
{
*errmsg = "socket";
return (-1);
}
/* Bind it to the specified device. */
snit.snit_family = AF_NIT;
strncpy(snit.snit_ifname, device, NITIFSIZ);
if (bind(fd, &snit, sizeof(snit)) != 0)
{
*errmsg = "bind";
return (-1);
}
/* Set up the input parameters. In this case, we don't want to */
/* do any input . . . */
bzero(&nioc, sizeof(nioc));
nioc.nioc_typetomatch = NT_NOTYPES;
if (ioctl(fd, SIOCSNIT, &nioc) != 0)
{
*errmsg = "ioctl";
return (-1);
}
/* All is well, return the file descriptor. */
return (fd);
}
/* MaKe an NIT socket for receiving (CHASTEly) packets on the */
/* device whose name is passed as a string through `device'. */
/* Packets received will be truncated to length `snaplen'. If the */
/* kernel buffer has not been filled within `tout' microseconds, the */
/* partial buffer collected by that time will be drained. A good value */
/* for `tout' is around 1000000 (one second). This routine is */
/* currently only guaranteed to work on ethernet devices. It returns */
/* a file descriptor if all goes well, or -1 if not (in this case errno */
/* will set to the error number, and errmsg will be pointed to a string */
/* that describes the attempted operation). */
extern int mk_nit_chaste(device, snaplen, tout, errmsg)
char *device; /* name of DEVICE to send on. */
int snaplen; /* packet SNAPshot LENgth. */
unsigned long tout; /* TimeOUT (microseconds). */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
/* Just dump this off on mk_nit_rcv. */
return (mk_nit_rcv(device,
0, /* non-promiscuous. */
NT_ALLTYPES,
snaplen,
tout,
errmsg));
}
/* MaKe an NIT socket for receiving (CHASTEly) packets on the */
/* device whose name is passed as a string through `device' that are */
/* of packet type `pktype'. Packets received will be truncated to */
/* length `snaplen'. If the kernel buffer has not been filled within */
/* `tout' microseconds, the partial buffer collected by that time will */
/* be drained. A good value for `tout' is around 1000000 (one second). */
/* This routine is currently only guaranteed to work on ethernet */
/* devices. It returns a file descriptor if all goes well, or -1 if */
/* not (in this case errno will set to the error number, and errmsg */
/* will be pointed to a string that describes the attempted operation). */
extern int mk_nit_chaste_filt(device, pktype, snaplen, tout, errmsg)
char *device; /* name of DEVICE to send on. */
unsigned int pktype; /* desired PacKet TYPEs. */
int snaplen; /* packet SNAPshot LENgth. */
unsigned long tout; /* TimeOUT (microseconds). */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
/* Just dump this off on mk_nit_rcv. */
return (mk_nit_rcv(device,
0, /* non-promiscuous. */
pktype,
snaplen,
tout,
errmsg));
}
/* MaKe an NIT socket for receiving (PROMISCuously) packets on the */
/* device whose name is passed as a string through `device'. */
/* Packets received will be truncated to length `snaplen'. If the */
/* kernel buffer has not been filled within `tout' microseconds, the */
/* partial buffer collected by that time will be drained. A good value */
/* for `tout' is around 1000000 (one second). This routine is */
/* currently only guaranteed to work on ethernet devices. It returns */
/* a file descriptor if all goes well, or -1 if not (in this case errno */
/* will set to the error number, and errmsg will be pointed to a string */
/* that describes the attempted operation). */
extern int mk_nit_promisc(device, snaplen, tout, errmsg)
char *device; /* name of DEVICE to send on. */
int snaplen; /* packet SNAPshot LENgth. */
unsigned long tout; /* TimeOUT (microseconds). */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
/* Just dump this off on mk_nit_rcv. */
return (mk_nit_rcv(device,
1, /* promiscuous. */
NT_ALLTYPES,
snaplen,
tout,
errmsg));
}
/* MaKe an NIT socket for receiving (PROMISCuously) packets on the */
/* device whose name is passed as a string through `device' that are */
/* of packet type `pktype'. Packets received will be truncated to */
/* length `snaplen'. If the kernel buffer has not been filled within */
/* `tout' microseconds, the partial buffer collected by that time will */
/* be drained. A good value for `tout' is around 1000000 (one second). */
/* This routine is currently only guaranteed to work on ethernet */
/* devices. It returns a file descriptor if all goes well, or -1 if */
/* not (in this case errno will set to the error number, and errmsg */
/* will be pointed to a string that describes the attempted operation). */
extern int mk_nit_promisc_filt(device, pktype, snaplen, tout, errmsg)
char *device; /* name of DEVICE to send on. */
unsigned int pktype; /* desired PacKet TYPEs. */
int snaplen; /* packet SNAPshot LENgth. */
unsigned long tout; /* TimeOUT (microseconds). */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
/* Just dump this off on mk_nit_rcv. */
return (mk_nit_rcv(device,
1, /* promiscuous. */
pktype,
snaplen,
tout,
errmsg));
}
/* MaKe an NIT socket for receiving packets on the device whose name is */
/* passed as a string through `device' that are of packet type */
/* `pktype'. If `promiscuous' is nonzero, then all packets will be */
/* looked at, instead of just those packets that were sent to this */
/* host. Packets received will be truncated to length `snaplen'. If */
/* the kernel buffer has not been filled within `tout' microseconds, */
/* the partial buffer collected by that time will be drained. A good */
/* value for `tout' is around 1000000 (one second). This routine is */
/* currently only guaranteed to work on ethernet devices. It returns a */
/* file descriptor if all goes well, or -1 if not (in this case errno */
/* will set to the error number, and errmsg will be pointed to a string */
/* that describes the attempted operation). */
extern int mk_nit_rcv(device, promiscuous, pktype, snaplen, tout, errmsg)
char *device; /* name of DEVICE to send on. */
int promiscuous; /* PROMISCUOUS input? */
unsigned int pktype; /* desired PacKet TYPEs. */
int snaplen; /* packet SNAPshot LENgth. */
unsigned long tout; /* TimeOUT (microseconds). */
char **errmsg; /* pointer to ERRor MeSsaGe. */
{
int fd; /* File Descriptor. */
struct nit_ioc nioc; /* Nit IOCtl parameter block. */
struct sockaddr_nit snit; /* Sockaddr for NIT socket. */
/* Make the socket. */
if ((fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW)) == -1)
{
*errmsg = "socket";
return (-1);
}
/* Bind it to the specified device. */
snit.snit_family = AF_NIT;
strncpy(snit.snit_ifname, device, NITIFSIZ);
if (bind(fd, &snit, sizeof(snit)) != 0)
{
*errmsg = "bind";
return (-1);
}
/* Set up the input parameters. */
bzero(&nioc, sizeof(nioc));
nioc.nioc_bufspace = 32768;
nioc.nioc_chunksize = snaplen;
nioc.nioc_typetomatch = pktype;
nioc.nioc_snaplen = snaplen;
nioc.nioc_bufalign = sizeof (int);
nioc.nioc_bufoffset = 0;
nioc.nioc_flags = ((tout == 0L) ? 0 : NF_TIMEOUT) |
((promiscuous == 0) ? 0 : NF_PROMISC);
nioc.nioc_timeout.tv_sec = tout / 1000000;
nioc.nioc_timeout.tv_usec = tout % 1000000;
if (ioctl(fd, SIOCSNIT, &nioc) != 0)
{
*errmsg = "ioctl";
return (-1);
}
/* Return the socket fd. */
return (fd);
}
/* NIT READ packets. This routine reads nit buffers from the specified */
/* nit socket. It breaks these buffers into packets. Each packet */
/* received will be passed to `rtn', which must be of the form: */
/* int rtn(nh, pk, len) */
/* struct nit_hdr *nh; Nit Header (NULL if invalid) */
/* char *pk; PacKet (NULL if invalid) */
/* int len; LENgth of pk. */
/* Rtn should return `1' if it wishes to receive more packets, `0' if */
/* it has seen enough. nit_read will return `1' if all went well and */
/* rtn eventually returned a `0', or nit_read will return `-1' if a */
/* system call failed (in this case errno will be set to the Unix error */
/* number and the pointer errmsg will be set to the name of the failing */
/* system call). In all other cases, nit_read will never return. */
extern int nit_read(fd, rtn, errmsg)
int fd; /* nit File Descriptor. */
int (*rtn)(); /* RouTiNe to pass packets to. */
char **errmsg; /* ERRor MeSsaGe. */
{
unsigned char buf[BUFSPACE]; /* capture BUFfer. */
int cc; /* Character Count. */
/* Each pass through the following loop reads one nit buffer */
/* from the kernel. */
while ((cc = read(fd, buf, sizeof (buf))) > 0)
{
register unsigned char *bp; /* Buffer Pointer. */
register unsigned char *bufstop; /* BUFfer STOP addr. */
int datalen; /* DATA LENgth. */
register struct nit_hdr *nh; /* Nit Header. */
unsigned char *pp; /* Packet Pointer. */
/* Call the routine with null packet to give it a */
/* chance to give up. */
if ((*rtn)(NULL, NULL, 0) == 0)
return (0);
/* Find the end of the nit buffer. */
bufstop = buf + cc;
/* Each pass through the following loop extracts one */
/* NIT header (possibly with packet data) from the nit */
/* buffer. */
for (bp = buf;
bp < bufstop;
bp += ((sizeof(struct nit_hdr) +
datalen +
sizeof(int) -
1) & ~(sizeof (int)-1)))
{
/* Get pointer to header. */
nh = (struct nit_hdr *)bp;
/* Set up pointer to data based on nit state. */
switch (nh->nh_state)
{
case NIT_CATCH :
pp = (unsigned char *)(bp + sizeof(*nh));
datalen = nh->nh_datalen;
break;
case NIT_SEQNO :
case NIT_NOMBUF :
case NIT_NOCLUSTER :
case NIT_NOSPACE :
pp = NULL;
datalen = 0;
break;
default :
/* NIT framing error, abort loop. */
nh = NULL;
pp = NULL;
datalen = 0;
bp = bufstop;
break;
}
/* Invoke caller's routine to handle the */
/* packet. */
if ((*rtn)(nh, pp, datalen) == 0)
return (0);
}
}
/* Got an error, let the caller know. */
*errmsg = "read";
return (-1);
}
/* NIT WRITE packet in raw mode. Note that the source address may be */
/* modified by the kernel to prevent obvious masquerade attempts. */
/* Stolen from the NIT(4p) man page. */
extern int nit_write(fd, buf, len)
int fd; /* nit File Descriptor. */
char *buf; /* output BUFfer. */
int len; /* LENgth of data to output. */
{
struct sockaddr sa; /* Socket Address. */
int offset; /* address part OFFSET. */
int retval; /* sendto RETurn VALue. */
extern int errno; /* ERRor NOmber. */
/* Set up socket address to contain first part of buffer. */
offset = sizeof(sa.sa_data);
if (len < offset)
{
errno = EINVAL;
return (-1);
}
sa.sa_family = AF_UNSPEC;
bcopy(buf, sa.sa_data, offset);
retval = sendto(fd, buf + offset, len - offset, 0, &sa, sizeof(sa));
if (retval == -1)
return (retval);
else
return (retval + offset);
}
RogueMonsterelse
echo "will not overwrite ./nit.c"
fi
if [ `wc -c ./nit.c | awk '{printf $1}'` -ne 13567 ]
then
echo `wc -c ./nit.c | awk '{print "Got " $1 ", Expected " 13567}'`
fi
if `test ! -s ./tx_hostname.3`
then
echo "writing ./tx_hostname.3"
cat > ./tx_hostname.3 << 'RogueMonster'
tx_hostname - Translate host name to internet address
#include <sys/types.h> #include <netinet/in.h> int tx_hostname(host, sa, em) char *host; struct sockaddr_in *sa; char **em;
If `tx_hostname' itself detects an error, a `-2' will be returned, and `errmsg' will be pointed to a human-readable description of the problem. The `errno' variable will be meaningless in this case.
/*
* $Log: tx_hostname.c,v $
* Revision 2.0 88/09/23 18:28:31 mckenney
* .
*
*/
/* Include files. */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <strings.h>
/* Type definitions local to this file. */
/* Functions exported from this file. */
extern int tx_hostname(); /* TranslateX HOSTNAME. */
/* Functions local to this file. */
/* Variables exported from this file. */
/* Variables local to this file. */
/* TranslateX HOSTNAME to internet address (the 'X' is silent). */
/* Returns -1 if there was a system call problem, points em to a string */
/* containing the system call name. */
/* Returns -2 if there were other problems and points em to a */
/* string containing a human-readable error message. */
/* Returns host address in sa. */
extern int tx_hostname(host, sa, em)
char *host; /* HOST name or id. */
struct sockaddr_in *sa; /* Socket Address. */
char **em; /* Error Message pointer. */
{
char errmsg[BUFSIZ]; /* ERRor MeSsaGe buffer. */
struct hostent *hp; /* Host entry Pointer. */
char *rerrmsg; /* Regex ERRor MeSsaGe. */
char *re_comp(); /* regex library routines. No */
int re_exec(); /* include files!!!!!! */
/* Initialize socket address. */
bzero((char *)sa, sizeof(*sa));
sa->sin_family = AF_INET;
/* Get host name -- check for internet address. */
if ((rerrmsg =
re_comp("[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"))
!=
(char *)0)
{
sprintf(errmsg, "re_comp error: %s, rerrmsg);
*em = errmsg;
return (-2);
}
if (re_exec(host) == 1)
{
u_long inet_addr(); /* Kludge around C bug. */
sa->sin_addr.s_addr = inet_addr(host);
}
else if ((hp = gethostbyname(host)) == NULL)
{
sprintf(errmsg, " *em = errmsg;
return (-2);
}
else
sa->sin_addr.s_addr = (u_long)hp->h_addr;
return (0);
}
RogueMonsterelse
echo "will not overwrite ./tx_hostname.c"
fi
if [ `wc -c ./tx_hostname.c | awk '{printf $1}'` -ne 2329 ]
then
echo `wc -c ./tx_hostname.c | awk '{print "Got " $1 ", Expected " 2329}'`
fi
echo "Finished archive 1 of 3"
exit